package cn.trigram.json;

import cn.trigram.exception.JsonDeserializerException;
import cn.trigram.exception.JsonSerializerException;
import cn.trigram.json.deserializer.BigNumberContextualDeserializer;
import cn.trigram.json.deserializer.TemporalContextualDeserializer;
import cn.trigram.json.serializer.BigNumberContextualSerializer;
import cn.trigram.json.serializer.LongSerializer;
import cn.trigram.json.serializer.TemporalContextualSerializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;


/**
 * Jackson工具类
 *
 * @version 1.0.0
 * @date 2022/08/02 09:10:56
 * @since 1.0.0
 */
@Slf4j
public class JacksonUtil {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    static {
        //https://blog.csdn.net/Xiaowu_First/article/details/123846121
        // 忽略json字符串中不识别的属性
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 忽略无法转换的对象
        OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        //不使用任何科学计数法的数值表达
        OBJECT_MAPPER.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
        // 指定时区
        OBJECT_MAPPER.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
        // 日期类型字符串处理
        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        // java8日期日期处理
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new TemporalContextualSerializer());
        javaTimeModule.addSerializer(LocalDate.class, new TemporalContextualSerializer());
        javaTimeModule.addSerializer(LocalTime.class, new TemporalContextualSerializer());
        javaTimeModule.addDeserializer(LocalDateTime.class, new TemporalContextualDeserializer());
        javaTimeModule.addDeserializer(LocalDate.class, new TemporalContextualDeserializer());
        javaTimeModule.addDeserializer(LocalTime.class, new TemporalContextualDeserializer());
        OBJECT_MAPPER.registerModule(javaTimeModule);
        final SimpleModule simpleModule = new SimpleModule("DefaultJacksonModule", Version.unknownVersion());
        simpleModule.addSerializer(Long.class, new LongSerializer());
        simpleModule.addSerializer(Long.TYPE, new LongSerializer());
        simpleModule.addSerializer(BigDecimal.class, new BigNumberContextualSerializer());
        simpleModule.addDeserializer(BigDecimal.class, new BigNumberContextualDeserializer());
        simpleModule.addSerializer(Date.class, new TemporalContextualSerializer());
        simpleModule.addDeserializer(Date.class, new TemporalContextualDeserializer());
        OBJECT_MAPPER.registerModule(simpleModule);
    }

    private static final XmlMapper XML_MAPPER = new XmlMapper();

    /**
     * 获取ObjectMapper
     *
     * @return {@link ObjectMapper }
     */
    public static ObjectMapper getObjectMapper() {
        return OBJECT_MAPPER;
    }

    /**
     * 获取XmlMapper
     *
     * @return {@link XmlMapper }
     */
    public static XmlMapper getXmlMapper() {
        return XML_MAPPER;
    }

    /**
     * 将对象转Json字符
     *
     * @param value
     * @return {@link String }
     */
    public static String toJson(Object value) {
        try {
            return getObjectMapper().writer().writeValueAsString(value);
        } catch (JsonProcessingException e) {
            throw new JsonSerializerException("jackson序列化异常", e);
        }
    }

    /**
     * 将对象转成被格式美化的字符
     *
     * @param value
     * @return {@link String }
     */
    public static String toPrettyJson(Object value) {
        try {
            return getObjectMapper().writer().withDefaultPrettyPrinter().writeValueAsString(value);
        } catch (JsonProcessingException e) {
            throw new JsonSerializerException("jackson序列化异常", e);
        }
    }

    /**
     * 从字符串转成clz指定的类
     *
     * @param content
     * @param clz
     * @return {@link R }
     */
    public static <R> R toObject(String content, Class<R> clz) {
        try {
            return getObjectMapper().readerFor(clz).readValue(content);
        } catch (JsonProcessingException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 将字符串反序列化，支持泛型
     * @param content JSON字符串
     * @param typeReference 泛型设置
     * @param <R> 泛型类
     * @return 实体类
     */
    public static <R> R toObject(String content, TypeReference<R> typeReference) {
        try {
            return getObjectMapper().readValue(content, typeReference);
        } catch (JsonProcessingException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    public static <R> R toObject(Map<String, Object> map, Class<R> clz) {
        return getObjectMapper().convertValue(map, clz);
    }

    /**
     * 从输入流转成clz指定的类
     *
     * @param reader
     * @param clz
     * @return {@link R }
     */
    public static <R> R toObject(Reader reader, Class<R> clz) {
        try {
            return getObjectMapper().readerFor(clz).readValue(reader);
        } catch (IOException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 从输入流转成clz指定的类
     *
     * @param inputStream
     * @param clz
     * @return {@link R }
     */
    public static <R> R toObject(InputStream inputStream, Class<R> clz) {
        try {
            return getObjectMapper().readerFor(clz).readValue(inputStream);
        } catch (IOException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 从json字符串转成集合，其中元素类型是clz指定的类
     *
     * @param content
     * @param clz
     * @return {@link List<R> }
     */
    public static <R> List<R> toList(String content, Class<R> clz) {
        try {
            return getObjectMapper().readerForListOf(clz).readValue(content);
        } catch (JsonProcessingException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 从输入流转成集合，其中元素类型是clz指定的类
     *
     * @param reader
     * @param clz
     * @return {@link List<R> }
     */
    public static <R> List<R> toList(Reader reader, Class<R> clz) {
        try {
            return getObjectMapper().readerForListOf(clz).readValue(reader);
        } catch (IOException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 从输入流转成集合，其中元素类型是clz指定的类
     *
     * @param inputStream
     * @param clz
     * @return {@link List<R> }
     */
    public static <R> List<R> toList(InputStream inputStream, Class<R> clz) {
        try {
            return getObjectMapper().readerForListOf(clz).readValue(inputStream);
        } catch (IOException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 从json字符串转成Map，其中value 的类型是clz指定的类
     *
     * @param content
     * @param clz
     * @return {@link Map<String, R> }
     */
    public static <R> Map<String, R> toMap(String content, Class<R> clz) {
        try {
            return getObjectMapper().readerForMapOf(clz).readValue(content);
        } catch (JsonProcessingException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 从输入流转成Map，其中value 的类型是clz指定的类
     *
     * @param reader
     * @param clz
     * @return {@link Map<String, R> }
     */
    public static <R> Map<String, R> toMap(Reader reader, Class<R> clz) {
        try {
            return getObjectMapper().readerForMapOf(clz).readValue(reader);
        } catch (IOException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 从输入流转成Map，其中value 的类型是clz指定的类
     *
     * @param inputStream
     * @param clz
     * @return {@link Map<String, R> }
     */
    public static <R> Map<String, R> toMap(InputStream inputStream, Class<R> clz) {
        try {
            return getObjectMapper().readerForMapOf(clz).readValue(inputStream);
        } catch (IOException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 从json字符串转成Map，其中value 的类型是Object
     *
     * @param content
     * @return {@link Map<String, Object> }
     */
    public static Map<String, Object> toMap(String content) {
        return toMap(content, Object.class);
    }

    /**
     * 从输入流转成Map，其中value 的类型是Object
     *
     * @param reader
     * @return {@link Map<String, Object> }
     */
    public static Map<String, Object> toMap(Reader reader) {
        return toMap(reader, Object.class);
    }

    /**
     * 从输入流转成Map，其中value 的类型是Object
     *
     * @param inputStream
     * @return {@link Map<String, Object> }
     */
    public static Map<String, Object> toMap(InputStream inputStream) {
        return toMap(inputStream, Object.class);
    }

    /**
     * 从json字符串转成数组，其中元素类型是clz指定的类
     *
     * @param content
     * @param clz
     * @return {@link R[] }
     */
    public static <R> R[] toArray(String content, Class<R> clz) {
        try {
            return getObjectMapper().readerForArrayOf(clz).readValue(content);
        } catch (JsonProcessingException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 从输入流转成数组，其中元素类型是clz指定的类
     *
     * @param reader
     * @param clz
     * @return {@link R[] }
     */
    public static <R> R[] toArray(Reader reader, Class<R> clz) {
        try {
            return getObjectMapper().readerForArrayOf(clz).readValue(reader);
        } catch (IOException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 从输入流转成数组，其中元素类型是clz指定的类
     *
     * @param inputStream
     * @param clz
     * @return {@link R[] }
     */
    public static <R> R[] toArray(InputStream inputStream, Class<R> clz) {
        try {
            return getObjectMapper().readerForArrayOf(clz).readValue(inputStream);
        } catch (IOException e) {
            throw new JsonDeserializerException("jackson反序列化异常", e);
        }
    }

    /**
     * 从Xml字符串转jackson的JsonNode
     *
     * @param xml 完整的包括xml声明的内容
     * @return {@link JsonNode }
     */
    public static JsonNode readForXml(String xml) {
        try {
            return XML_MAPPER.reader().readTree(xml);
        } catch (JsonProcessingException e) {
            throw new JsonDeserializerException("jackson-xml-mapper反序列化异常", e);
        }
    }

    /**
     * 从Xml字符串转jackson的JsonNode
     *
     * @param xmls 多个
     * @return {@link JsonNode }
     */
    public static JsonNode readForXml(String... xmls) {
        try {
            final StringBuilder builder = new StringBuilder().append("<_element_container_>");
            for (String xml : xmls) {
                builder.append(xml);
            }
            builder.append("</_element_container_>");
            return XML_MAPPER.reader().readTree(builder.toString());
        } catch (JsonProcessingException e) {
            throw new JsonDeserializerException("jackson-xml-mapper反序列化异常", e);
        }
    }

    /**
     * 从dom4j的Node类转jackson的JsonNode
     *
     * @param node 完整的xml文件的node对象
     * @return {@link JsonNode }
     */
    public static JsonNode readForXml(Node node) {
        try {
            return XML_MAPPER.reader().readTree(node.asXML());
        } catch (JsonProcessingException e) {
            throw new JsonDeserializerException("jackson-xml-mapper反序列化异常", e);
        }
    }

    /**
     * 从dom4j的Node类转jackson的JsonNode
     *
     * @param nodes 多个xml片段
     * @return {@link JsonNode }
     */
    public static JsonNode readForXml(Node... nodes) {
        try {
            final Element container = DocumentHelper.createElement("_element_container_");
            for (Node node : nodes) {
                node.setParent(null);
                container.add(node);
            }
            return XML_MAPPER.reader().readTree(container.asXML());
        } catch (JsonProcessingException e) {
            throw new JsonDeserializerException("jackson-xml-mapper反序列化异常", e);
        }
    }
}